<?php
/**
 * @brief Klasa kontrolera auctions
 *
 * Klasa udostępnia akcje odpowiedzialne za pasywne uczestnictwo w aukcjach, 
 * czyli przeglądanie listy aukcji oraz ich szczegółów. Żadna z akcji nie
 * wymaga wcześniejszego logowania, ale po zalogowaniu, w określonych
 * przypadkach,
 * wyświetlane są dodatkowe informacje. 
 *
 *
 */

class AuctionsController extends Zend_Controller_Action
{

    protected $_user = null; /*!< Informacje zalogowanego uzytkownika. */

    protected $request = null; /*!< Parametry zadania. */

    protected $mapper = null; /*!< Mapper aukcji. */

    /**
     * @brief Standardowa metoda poprzedzająca działanie akcji.
     *
     * Przed wykonaniem akcji, przekazywany jest do wyświetlenia widok pomocniczy
     * nagłówka strony, pobierane są wiadomości z flashMessengera oraz pobierane
     * są
     * dane użytkownika z Zend_Auth.  
     *
     *
     *
     *
     */
    public function preDispatch()
    {
        $this->view->render('utility/_headbox.phtml');
        $this->_flashMessenger = $this->_helper->getHelper('FlashMessenger');
        $this->view->messages = $this->_flashMessenger->getMessages();
        $this->request = $this->getRequest();
        $this->mapper = new Application_Model_AuctionMapper();
        
        $auth = Zend_Auth::getInstance();
        if($auth->hasIdentity()){
            $this->_user = $auth->getIdentity();
        }
        
        $ajaxContext = $this->_helper->getHelper('AjaxContext');
        $ajaxContext->addActionContext('results', 'json')
                ->initContext();
    }

    /**
     * @brief Akcja index
     *
     * Wsywietla sie w wiedoku tej akcji nierozpoczete aukcje.
     * Mozna je tam edytowac i rozpoczac.
     * Mozna tu tez zaczac tworzenie nowej aukcji.
     * 
     */
    public function indexAction()
    {
        $this->actionIsProtected();
        
        $query = ('MarketEntity_id = "'.$this->_user->login.'" and startTime is NULL');
        $mapper = new Application_Model_AuctionMapper();
        $auctions = $mapper->fetchAll($query);
        
        $this->view->auctions = $auctions;
        
    }

    /**
     * @brief Akcja browse
     *
     * Akcja wyświetlająca listę trwających aukcji. Lista aukcji może być 
     * filtrowana ze względu na czas pozostały do końca aukcji oraz widoczność
     * ofert. Możliwe jest również wyszukiwanie słów w tytułach aukcji.
     *
     */
    public function browseAction()
    {
        //pobranie formularza i wysłanie do widoku
        $form = new Application_Form_Search();
        $this->view->form =  $form;
        
        //pobranie parametrów GET
        $request = $this->getRequest();
        
        $page = $request->getParam('page');
        $ex = $request->getParam('ex');
        $period = $request->getParam('period');
        $key = $request->getParam('key');
        //tworzenie zapytania na podstawie pobranych parametrów
        $query = 'endTime > now() ';

        switch ($period) {
            case 1:
                $query .= 'AND endTime < "'.$this->addHours(1+1).'" ';
                break;          
            case 2:
                $query .= 'AND endTime < "'.$this->addHours(5+1).'" ';
                break;           
            case 3:
                $query .= 'AND endTime < "'.$this->addHours(12+1).'" ';
                break;            
            case 4:
                $query .= 'AND endTime < "'.$this->addHours(24+23).'" ';
                break;            
            case 5:
                $query .= 'AND endTime < "'.$this->addHours(3*24).'" ';
                break;            
        }

        if(!empty($key)){
            $query .= 'AND title LIKE "%'.$key.'%" ';
        }
        
        //wyszukanie listy aukcji spełniających kryteria
        $mapper = new Application_Model_AuctionMapper();
        $auctions = $mapper->fetchAll($query);
        //przekazanie listy do paginatora, dzielącego je na strony
        $paginator = new Zend_Paginator(new Zend_Paginator_Adapter_Array($auctions));
        $paginator->setCurrentPageNumber($page);
        $paginator->setItemCountPerPage(35);
        $this->view->paginator = $paginator;     
        
    }

    /**
     * @brief Akcja details
     *
     * Akcja wyświetlająca szczegóły aukcji. 
     *
     */
    public function detailsAction()
    {
        //pobieranie aukcji o podanym id
        $auction = $this->getAuction();

        //przekaznie szczegółów aukcji do widoku
        $this->view->auction = $auction;
        //sprawdzenie statusu oferty
        $_end = $auction->getStartTime();
        if(empty($_end)){
            $this->view->status = 'prep';
            $login = $auction->getMarketEntity_id();
            $this->actionAuthorizedFor($login);
        } else {
            $date = new Zend_Date($auction->getEndTime());
            if($date->isLater(Zend_Date::now())){
                $this->view->status = 'open';
            } else {
                $this->view->status = 'closed';
            }
        }
        
        $winner = $this->getWinners($auction->getAuction_id());
        $this->view->winners = $winner;
        
        
        $offerMapper = new Application_Model_OfferMapper();
        $query = "MarketEntity_id = '".$this->_user->login.
                "' and firstOffer = 1 and Auction_id = ".
                $auction->getAuction_id()." ";
        $offers = $offerMapper->fetchAll($query);
        //var_dump($offers);
        $this->view->offers = $offers;
        
        $mapper = new Application_Model_CommodityMapper();
        $commodities = $mapper->fetchByAuction($auction->getAuction_id());
        $this->view->commodities = $commodities;
        $this->view->user = $this->_user->login;
        

    }

    /**
     * @brief Akcja new
     *
     * Wsywietla sie w wiedoku tej akcji nierozpoczete aukcje.
     * Mozna je tam edytowac i rozpoczac.
     * Mozna tu tez zaczac tworzenie nowej aukcji.
     */
    public function newAction()
    {
        $this->actionIsProtected();
        $mapper = new Application_Model_AuctionMapper();
        $form = new Application_Form_Auction();
        
        
        $this->view->form = $form;
        if($this->request->isPost()){
            if($form->isValid($this->request->getPost())){
                $values = $form->getValues();
                $auction = new Application_Model_Auction($values);
                $auction->setMarketEntity_id($this->_user->login);
                $auction->setIsVisible(0);
                $mapper->save($auction);
                $this->_helper->flashMessenger
                        ->addMessage('success/Nowa aukcja czeka na akceptację');
                $this->_helper->redirector('index','auctions');
            }
        }
    }
    
    /**
     * @brief Akcja edit
     *
     * Akcja edycji aukcji.
     */
    public function editAction()
    {
        $this->actionIsProtected();
        $auction = $this->getAuction(TRUE); 
        $form = new Application_Form_Auction();
        
        
        if($this->request->isPost()){
            if($form->isValid($this->request->getPost())){
                $values = $form->getValues();                
                $auction->setOptions($values);
                $this->mapper->save($auction);
                $this->_helper->flashMessenger
                        ->addMessage('success/Nowa aukcja czeka na akceptację');
                $this->_helper->redirector('index','auctions');
            }
        } else {
            $data = Array();
            $data['title'] = $auction->getTitle();
            $data['description'] = $auction->getDescription();
            $data['duration'] = $auction->getDescription();
            
            $form->populate($data);
        }
        
        $this->view->form = $form;
    }

    /**
     * @brief Akcja start
     *
     * Akcja rozpoczyna aukcje jezeli zostala w niej zdefiniowana
     * conajmniej jedna oferta
     */
    public function startAction()
    {
        $auction = $this->getAuction(TRUE);
        if(count($auction->getOffers()) == 0) {
            $this->_helper->flashMessenger
                        ->addMessage('error/W aukcji nie ma twojej oferty');
            $this->_helper->redirector('index','auctions');
        }
        if($auction->getEndTime() == NULL) {
            $date = Zend_Date::now();
            $auction->setStartTime($date->getIso());
            $duration = $auction->getDuration();
            $date->add($duration, Zend_Date::DAY);
            $auction->setEndTime($date->getIso());
            $this->mapper->save($auction);
        }
        $this->_helper->redirector('browse','auctions');
    }
    
    /**
     * @brief Akcja results
     *
     * Akcja zwraca w ajaxom kontekscie wyniki aukcji. Sa one wyswietlane
     * na ekranach aukcji i szczegolow ofert.
     * Po zakonczeniu aukcji, pierwsze wywolanie tej metody spowoduej zapis
     * danych w bazie danych. 
     */
    public function resultsAction()
    {
        // action body
        $auctionId = $this->request->getParam('auction');
        //$Offer = $this->request->getParam('Offer');
        $balance = new Application_Model_Balancing($auctionId);
        $auction = $this->mapper->find($auctionId);
        $open = true;
        if($auction->getIsVisible() == 0){
            $end = $auction->getEndTime();
            $endTime= new Zend_Date($end);
            if(!empty($end) && $endTime->isEarlier(Zend_Date::now())) {
                $open =  false;
                $auction->setIsVisible(1);
                $this->mapper->save($auction);
            } 
        }
//        $start = microtime(true);
        $results = $balance->makeMagic(!$open);
//        $end = microtime(true);
//        echo $end - $start;
        
        $this->view->results = $results;
    }
    /**
     * @brief Akcja commodity details
     *
     * Metoda wyświetlająca szczegóły towaru
     *
     */
    public function commodityDetailsAction()
    {
        ///do kasacji
    }

    /**
     * @brief Standardowa metoda wykonywana po zakończeniu wykonywania akcji
     *
     * Umożliwia wyświetlenie stopki strony.
     *
     */
    public function postDispatch()
    {
        $this->view->render('utility/_footbox.phtml'); 
    }

    /**
     * @brief Metoda zwracająca czas odległy o parę godzin
     *
     * Metoda pomocnicza zwracająca datę oddaloną o określoną ilość godzin
     * w formacie przyjaznym dla bazy danych.
     *
     * @param int $hours godziny
     * @return string Data w formacie YYYY-MM-dd HH:mm:ss
     *
     */
    private function addHours($hours)
    {
        $date = Zend_Date::now();
        $date->addHour($hours);
        return $date->toString('YYYY-MM-dd HH:mm:ss');
    }

    /**
     * @brief Metoda sprawdzajca zalogowanie usytkownika
     *
     * Jezeli usytkownik nie jest zalogowany to bedzie o to poproszony
     * na innym ekranie.
     */
    private function actionIsProtected()
    {
        if(empty($this->_user)) {
            $this->_helper->flashMessenger->addMessage("warning/Zaloguj się!");
            $this->_helper->redirector('login','auth');
        }
    }

    /**
     * @brief Metoda chroniaca poszczegolne akcjie
     *
     * Jezeli usytkownik nie posiada uprawnien do wykonania akcji
     * to zostanie wyrzucony wyjatek.
     */
    private function actionAuthorizedFor($login)
    {
        $loggedUser = $this->_user->login;
        if(empty($loggedUser)||
                $loggedUser != $login)
            throw new Exception('Odmowa dostępu');
    }

    /**
     * @brief Metoda zawracajaca obiekt aukcji
     *
     * Za pomoca mappera wydobywane sa z bazy danych informacje o aukcji.
     */
    private function getAuction($protected = false)
    {
        $id = $this->request->getParam('id');
        if(empty($id))
            throw new Zend_Controller_Action_Exception('Niepoprawne Id oferty', 404);
        //wez aukcje
        $auction = $this->mapper->find($id);
        if(empty($auction) )
            throw new Zend_Controller_Action_Exception('Nie ma aukcji o tym numerze', 404);
        
        if($protected) {
            //sprawdz czy oferta nalezy do uzytkownika
            $this->actionIsProtected();
            $login = $auction->getMarketEntity_id();
            $this->actionAuthorizedFor($login);
        }
        
        return $auction;
    }

    /**
     * @brief Metoda zawracajaca zwyciezcowa aukcji
     *
     * Jezeli okreslonego uzytkownika nie ma na liscie zwyciezcow to
     * nie otrzyma on informacji o danych kontaktowych pozostalych
     * uczestnikow licytacji.
     */
    private function getWinners($id) {
        $query = 'Auction_id = '.$id.' and acceptedVolume > 0 and firstOffer = 1'; 
        $mapper = new Application_Model_OfferMapper();
        $offers = $mapper->fetchAll($query);
        $winners = Array();
        $currentUser = $this->_user->login;
        $skip = true;
        foreach ($offers as $offer ) {
            $user = $offer->getMarketEntity_id();
            if($user == $currentUser) {
                $skip = false;
            }
            if(!array_key_exists($user, $winners)) {
                $userMapper = new Application_Model_MarketEntityMapper();
                $userObj = $userMapper->find($user);               
                $winners[$user] = $userObj;
            }
        }
        if($skip) {
            return Array(); 
        }
        return $winners;
    }
}

